/*************************************************************************
 *                                                                       *
 * This file is part of the FreeMAPs distribution.  For full copyright   *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 * Date:             2014.04.04                                          *
 * Description:      bi-map so that the value can be used as key         *
 *                                                                       *
 *************************************************************************/

#ifndef FreeMAPs_include_COMMON_tbox_Bimap_h
#define FreeMAPs_include_COMMON_tbox_Bimap_h

#include "FreeMAPsConfig.h"

//C++ headers
#include <map>
#include <vector>

//COMMON headers
#include "COMMON/base/Common.h"

namespace FreeMAPs
{

/**
 * @brief used for the map that can find key by it's value.
 *
 * that means both the key and the value will be identity.
 */
template <typename Key, typename Value>
class Bimap
{
public:

    typedef typename std::map<Key, Value>::const_iterator const_iterator;
    typedef typename std::map<Value, Key>::const_iterator const_swap_iterator;

public:

    inline
    Bimap ();

public:

    inline void
    clear();

    /**
     * insert a pair,
     * make sure the key and value are not in the map.
     * otherwise error will be report and exit.
     */
    inline void
    insert (
        const Key& k,
        const Value& v);

    inline bool
    is_empty() const;

    inline std::size_t
    size() const;

    inline bool
    has_key(
        const Key& k) const;

    inline bool
    has_value(
        const Value& v) const;

    inline bool
    has_pair (
        const Key& k,
        const Value& v) const;

    /**
     * @return the value by it key.
     * make sure the v is exists, otherwise error will be reported and exit.
     */
    inline const Value&
    get_value (const Key& k)const;

    /**
     * @return the key by it value.
     * make sure the v is exists, otherwise error will be reported and exit.
     */
    inline const Key&
    get_key (const Value& v)const;

    inline const_iterator
    begin()const;

    inline const_iterator
    end()const;

    inline const_swap_iterator
    swap_begin()const;

    inline const_swap_iterator
    swap_end()const;

    inline const std::map<Key, Value>&
    get_key_map() const;

    inline const std::map<Value, Key>&
    get_value_map() const;

    /**
     * @return the key vector,
     * if in_key_order is ture, order in key,
     * else order in value
     */
    inline std::vector<Key>
    get_key_vector (
        const bool in_key_order = true) const;

    inline std::vector<Value>
    get_value_vector (
        const bool in_key_order = true) const;

    inline std::set<Key>
    get_key_set() const;

    inline std::set<Value>
    get_value_set() const;

    inline void
    erase_by_key (
        const Key& key);

    inline void
    erase_by_value (
        const Value& value);

private:

    std::map<Key, Value> d_from_key_to_value;
    std::map<Value, Key> d_from_value_to_key;
};

}

#include "COMMON/tbox/Bimap.inl"

#endif
